package com.yinsin.security;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;

import com.yinsin.other.LogHelper;
import com.yinsin.utils.ByteUtils;
import com.yinsin.utils.Constants;
import com.yinsin.utils.FileUtils;
import com.yinsin.utils.ObjectUtils;

/**
 * RAS加解密工具:
 * <ul>
 * <li>生成公钥与私钥</li>
 * <li>根据公/私钥文件获取公/私钥对象</li>
 * <li>RAS加密，返回String</li>
 * <li>RAS加密，返回byte[]</li>
 * <li>RAS解密，返回String</li>
 * <li>RAS解密，返回byte[]</li>
 * </ul>
 * @author Yisin
 *
 */
public class RSA {
    private static final LogHelper log = LogHelper.getLogger(RSA.class);

    /**
     * 生成公钥与私钥
     * @param pubkeyfile
     * @param prikeyfile
     * @return
     * @throws NoSuchAlgorithmException
     * @throws FileNotFoundException
     * @throws IOException
     */
    public static boolean makekeyfile(String pubkeyfile, String prikeyfile) throws NoSuchAlgorithmException, FileNotFoundException, IOException {
        boolean result = false;
        FileUtils.createFile(pubkeyfile);
        FileUtils.createFile(prikeyfile);
        
        // KeyPairGenerator类用于生成公钥和私钥对，基于RSA算法生成对象
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        // 初始化密钥对生成器，密钥大小为1024位
        keyPairGen.initialize(1024);
        // 生成一个密钥对，保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();

        // 得到私钥
        Key privateKey = (RSAPrivateKey) keyPair.getPrivate();
        // 生成私钥
        ObjectUtils.objectToFile(privateKey, prikeyfile);

        // 得到公钥
        Key publicKey = (RSAPublicKey) keyPair.getPublic();
        // 生成公钥
        ObjectUtils.objectToFile(publicKey, pubkeyfile);
        
        result = true;
        return result;
    }

    /**
     * 
     * @param k
     * @param data
     * @param encrypt
     *            1 加密 0解密
     * @return
     * @throws Exception
     */
    private static byte[] handleData(Key k, byte[] data, int encrypt) throws Exception {
        if (k != null) {  
            Cipher cipher = Cipher.getInstance("RSA");  
            if (encrypt == 1) {  
                cipher.init(Cipher.ENCRYPT_MODE, k);  
                byte[] resultBytes = cipher.doFinal(data);  
                return resultBytes;  
            } else if (encrypt == 0) {  
                cipher.init(Cipher.DECRYPT_MODE, k);  
                byte[] resultBytes = cipher.doFinal(data);  
                return resultBytes;  
            }  
        }
        return null;
    }
    
    /**
     * 根据公/私钥文件获取公/私钥对象
     * @param pubfile
     * @return
     */
    public static Key getRSAKey(String pubfile){
        Key pubkey = null;
        try {
            pubkey = ObjectUtils.fileToObject(pubkey, pubfile);
        } catch (Exception e) {
            log.error("getRSAKey is error:" + e.getMessage());
        }
        return pubkey;
    }
    
    /**
     * RAS加密，返回String
     * @param keyfile 公/私钥文件
     * @param data 要被加密的数据
     * @return String
     */
    public static String encrypt(String keyfile, String data){
        String str = null;
        Key key = getRSAKey(keyfile);
        try {
            byte[] result = handleData(key, data.getBytes(Constants.CHARSET_UTF8), 1);
            str = ByteUtils.parseByte2HexStr(result);
        } catch (Exception e) {
            log.error("encrypt is error:" + e.getMessage());
        }
        return str;
    }
    
    /**
     * RAS加密，返回byte[]
     * @param keyfile 公/私钥文件
     * @param data 要被加密的数据
     * @return byte[]
     * @throws UnsupportedEncodingException
     * @throws Exception
     */
    public static byte[] encryptToByte(String keyfile, String data) throws UnsupportedEncodingException, Exception{
        return handleData(getRSAKey(keyfile), data.getBytes(Constants.CHARSET_UTF8), 1);
    }
    
    /**
     * RAS解密，返回String
     * @param keyfile 公/私钥文件
     * @param data 要被解密的密文
     * @return String
     */
    public static String decrypt(String keyfile, String data){
        String str = null;
        Key pubkey = getRSAKey(keyfile);
        try {
            byte[] result = handleData(pubkey, ByteUtils.parseHexStr2Byte(data), 0);
            str = new String(result, Constants.CHARSET_UTF8);
        } catch (Exception e) {
            log.error("decrypt is error:" + e.getMessage());
        }
        return str;
    }
    
    /**
     * RAS解密，返回byte[]
     * @param keyfile 公/私钥文件
     * @param data 要被解密的密文
     * @return byte[]
     * @throws UnsupportedEncodingException
     * @throws Exception
     */
    public static byte[] decryptToByte(String keyfile, byte[] data) throws UnsupportedEncodingException, Exception{
        return handleData(getRSAKey(keyfile), data, 0);
    }
}
